/*
 * Copyright (c) [2005] [Jeffrey Moore]
 *
 * Redistributions in source code form must reproduce the above copyright and
 * this condition.
 *
 * The contents of this file are subject to the Sun Project JXTA License
 * Version 1.1 (the "License"); you may not use this file except in compliance
 * with the License. A copy of the License is available at
 * http://www.jxta.org/jxta_license.html.
 *
 */

/*
* ViJxtaDialogView.java
*
* Created on April 11, 2005, 9:26 AM
*/

package net.jxta.myjxta.plugins.vijxta;

import info.clearthought.layout.TableLayout;
import net.jxta.logging.Logging;
import net.jxta.myjxta.View;
import net.jxta.myjxta.dialog.Dialog;
import net.jxta.myjxta.plugin.PluginView;
import net.jxta.myjxta.util.Resources;
import net.jxta.myjxta.util.exec.ExecFactory;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Jeff Moore
 */
public final class ViJxtaDialogView extends JPanel implements PluginView {

    static final Logger LOG = Logger.getLogger(ViJxtaDialogView.class.getName());

    private static final ResourceBundle STRINGS = Resources.getStrings();
    //hACK!

    public static final String CONFIG_VIDEO_SOURCE_PANEL = "configVideoSource";

    public static final String CONFIG_LOCAL_DEVICES_PANEL = "configLocalDevices";

    public static final String CONFIG_NETWORKED_DEVICES_PANEL = "configNetworkedDevices";

    public static final String INITIATED_LOCALLY = "ViJxtaDialogInitiatedLocally";


    private static final String CONFIG_FORMATS_PANEL = "configFormats";

    private static final String CONFIG_TEST_PANEL = "configTest";

    private static final String CONFIG_PANEL = "configPanel";

    private static final String NO_RESPONSE_PANEL = "noResponsePanel";

    private static final String CONFIG_LOCAL_OPTIONS_PANEL = "configLocalOptionsPanel";

    private static final String CALL_CONTROL_PANEL = "callControlPanel";

    private static final String STATS_PANEL = "statsPanel";

    private static final String ERROR_PANEL = "errorPanel";

    private static final String IDLE_PANEL = "idlePanel";

    private static final String URL_JMF_DOWNLOAD = "http://java.sun.com/products/java-media/jmf/2.1.1/download.html";

    private static final String JMF_ERROR_MESSAGE = "<html><font color=blue><u>Download Java Media Framework</u></font></html>";

    /**
     * sleep time for the UI update thread
     */

    private static final int UI_UPDATE_INTERVAL = 1000;

    /**
     * sleep time while waiting for dialog pipe to connect
     */

    private static final int CONNECT_SLEEP_TIME = 200;


    private final JButton startCallButton = null;

    private JButton endCallButton = null;


    private JSlider imageQualitySlider = null;

    private JLabel messageLabel = null;

    private JLabel incomingBufferSizeLabel = null;


    private JLabel outgoingBufferSizeLabel = null;


    private final JLabel sessionLogFileNameLabel = null;

    private JLabel incomingImageCompressionLabel = null;

    private JLabel outgoingImageCompressionLabel = null;

    private JLabel productLabel = null;

    private final JCheckBox speakerMuteCheckBox = null;

    private final JCheckBox saveConvoCheckBox = null;

    private JLabel bytesReceivedLabel = null;

    private JLabel messagesReceivedLabel = null;

    private JLabel roundTripTimeLabel = null;

    private JLabel bytesSentLabel = null;

    JCheckBox transmitCheckBox = null;

    JCheckBox receiveCheckBox = null;

    private JLabel messagesSentLabel = null;

    private CardLayout cardLayout = null;

    private JPanel deckPanel = null;

    private CardLayout configCardLayout = null;

    private JPanel configDeckPanel = null;

    private final JLabel speakerLabel = null;

    private JButton statsButton = null;

    private JLabel jmfErrorLabel = null;

    private final JLabel encodedBufferSizeLabel = null;

    private JLabel errorMessageLabel = null;

    private final JLabel encodedBlockSizeLabel = null;

    private JLabel callElapsedTimeLabel = null;

    private JLabel callStartTimeLabel = null;

    private JLabel callEndTimeLabel = null;

    private JLabel outgoingMessagesPerSecondLabel = null;

    private JLabel incomingMessagesPerSecondLabel = null;

    private JLabel outgoingBytesPerSecondLabel = null;

    private JLabel incomingBytesPerSecondLabel = null;

    private final JLabel compressionRatioLabel = null;

    private final JLabel qualityLabel = null;

    private JLabel averageDecodeTimeLabel = null;

    private JLabel averageEncodeTimeLabel = null;

    private JLabel decodeTimeLabel = null;

    private JLabel encodeTimeLabel = null;

    private JLabel protocolStateLabel = null;

    private JLabel refreshRateLabel = null;

    private final JLabel encodedMessageSizeLabel = null;

    private JList captureDevicesList = null;

    private JList formatsList = null;

    private JPanel monitorTestPanel = null;


    private boolean inSession = false;

    final Insets panelInsets = null;

    private ViJxtaDialog viJxtaDialog = null;

    final Insets subComponentInsets = null;


    private boolean initiatedLocally = false;

    private View myJxtaView = null;

    private ViJxtaCallControl viJxtaCallControl = null;

    private Thread updateThread = null;

    private boolean updateThreadRun = true;

    long previousOutgoingMessagesValue = 0;

    long previousIncomingMessagesValue = 0;

    long previousOutgoingBytesValue = 0;

    long previousIncomingBytesValue = 0;

    private boolean noLocalCaptureDevicesFound = false;

    private Hashtable imageQualityLabelTable = null;


    private Component monitorTestComponent = null;

    private final Component localMonitorComponent = null;

    private final Component remoteMonitorComponent = null;

    private JPanel localMonitorPanel = null;

    private JPanel remoteMonitorPanel = null;

    private JButton placeAcceptCallButton = null;

    private final JPanel messagePanel = null;

    private JButton holdResumeCallButton = null;

    private JSlider refreshRateSlider = null;

    private boolean isJMFPresent = false;

    private boolean localDevice = false;

    private boolean networkedDevice = false;

    private boolean noDevice = false;

    private JTextField networkedSourceURLTextField = null;

    private JTextField authenticationUserNameTextField = null;

    private JPasswordField authenticationPasswordTextField = null;

    private JCheckBox authenticationCheckBox = null;


    /**
     * Creates a new instance of ViJxtaDialogView
     */
    public ViJxtaDialogView(View p_view, Dialog dialog, boolean p_locallyInitiated) {

        super();
        initiatedLocally = p_locallyInitiated;

        LOG.setLevel(Level.INFO);

        imageQualityLabelTable = new Hashtable();

        imageQualityLabelTable.put(new Integer(0), new JLabel("0%"));

        imageQualityLabelTable.put(new Integer(20), new JLabel("20%"));

        imageQualityLabelTable.put(new Integer(40), new JLabel("40%"));

        imageQualityLabelTable.put(new Integer(60), new JLabel("60%"));

        imageQualityLabelTable.put(new Integer(80), new JLabel("80%"));

        imageQualityLabelTable.put(new Integer(100), new JLabel("100%"));


        this.myJxtaView = p_view;

        this.viJxtaDialog = (ViJxtaDialog) dialog;


        if (!this.viJxtaDialog.isConnected()) {

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("Constructor : ViJxtaDialog not connected");
            }

            dismiss();

        } else {

            UI();

            /** test for jmf.jar. if jmf is not present then move to errorpane and ditch plugin
             *  protocol will never be sent.
             */

            //tests for jmf.jar

            try {

                this.isJMFPresent = LocalDeviceMonitorControl.isJMFPresent();

            } catch (Exception x) {

                x.printStackTrace();

                isJMFPresent = false;

            } catch (Error e) {

                e.printStackTrace();

                isJMFPresent = false;
            }


            this.viJxtaCallControl = new ViJxtaCallControl(this, this.myJxtaView, viJxtaDialog, initiatedLocally);

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("viJxtaCall Control is " + this.viJxtaCallControl);
            }

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("viJxtaCall Control is " + this.getCallControl());
            }

            /** UI update thread for stats, call times etc*/
            updateThread = new Thread(new Runnable() {
                public void run() {

                    while (updateThreadRun) {
                        EventQueue.invokeLater(new Runnable() {
                            public void run() {

                                long tmp = 0;

                                if (getCallControl().getLocalMonitorControl().isTransmit()) {
                                    refreshRateLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getRefreshRate()) + " fps");

                                    bytesSentLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getBytesSent()));

                                    messagesSentLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getMessagesSent()));

                                    outgoingImageCompressionLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getImageCompression()));

                                    tmp = getCallControl().getLocalMonitorControl().getMessagesSent();
                                    outgoingMessagesPerSecondLabel.setText(String.valueOf(
                                            tmp - previousOutgoingMessagesValue));
                                    previousOutgoingMessagesValue = tmp;


                                    tmp = getCallControl().getLocalMonitorControl().getBytesSent();
                                    outgoingBytesPerSecondLabel.setText(String.valueOf(
                                            tmp - previousOutgoingBytesValue));
                                    previousOutgoingBytesValue = tmp;

                                    encodeTimeLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getImageEncodeTime()));

                                    averageEncodeTimeLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getAverageImageEncodeTime()));

                                    outgoingBufferSizeLabel.setText(String.valueOf(getCallControl().getLocalMonitorControl().getBufferSize()));


                                }

                                bytesReceivedLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getBytesReceived()));

                                messagesReceivedLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getMessagesReceived()));

                                incomingImageCompressionLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getImageCompression()));

                                roundTripTimeLabel.setText(String.valueOf(getCallControl().getRoundTripTime()));

                                callEndTimeLabel.setText(getCallControl().getCallEndTimeString());

                                callStartTimeLabel.setText(getCallControl().getCallStartTimeString());

                                callElapsedTimeLabel.setText(getCallControl().getCallElapseTimeString());

                                tmp = getCallControl().getRemoteMonitorControl().getMessagesReceived();
                                incomingMessagesPerSecondLabel.setText(String.valueOf(
                                        tmp - previousIncomingMessagesValue));
                                previousIncomingMessagesValue = tmp;

                                tmp = getCallControl().getRemoteMonitorControl().getBytesReceived();
                                incomingBytesPerSecondLabel.setText(String.valueOf(
                                        tmp - previousIncomingBytesValue));
                                previousIncomingBytesValue = tmp;

                                decodeTimeLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getImageDecodeTime()));

                                averageDecodeTimeLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getAverageImageDecodeTime()));


                                incomingBufferSizeLabel.setText(String.valueOf(getCallControl().getRemoteMonitorControl().getBufferSize()));
                            }
                        });

                        try {

                            Thread.sleep(UI_UPDATE_INTERVAL);

                        } catch (InterruptedException ix) {
                            ix.printStackTrace();
                        }
                    }

                }
            });

            updateThread.setDaemon(true);
            updateThread.setPriority(Thread.MIN_PRIORITY);

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("before init session");
            }

            this.getCallControl().initSession();

            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("after init session");
            }

        }
    }


    public void protocolStateChanged(int protocolState) {


        if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_INVITE_REQUEST_SENT) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_INVITE_REQUEST + " Sent");

            showPanel(this.CONFIG_PANEL);

            showConfigPanel(this.CONFIG_VIDEO_SOURCE_PANEL);

        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_INVITE_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_INVITE_REQUEST + " Received");

            String tmpString = this.getCallControl().getRemoteMonitorControl().getOriginator();

            final String originator = tmpString == null ? "Unknown Remote" : tmpString;

            final String localPeer = this.myJxtaView.getControl().getPeerName();

            this.myJxtaView.updatePluginPanel(this, originator);

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(false);

                    endCallButton.setEnabled(true);

                    statsButton.setEnabled(true);

                    placeAcceptCallButton.setText(STRINGS.getString("action.vijxta.acceptcall"));

                    placeAcceptCallButton.setEnabled(false);


                    remoteMonitorPanel.setBorder(new TitledBorder(originator));

                    localMonitorPanel.setBorder(new TitledBorder(localPeer));

                }
            });

            showPanel(this.CONFIG_PANEL);

            showConfigPanel(this.CONFIG_VIDEO_SOURCE_PANEL);


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_INVITE_ACCEPT_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_INVITE_ACCEPT + " Received");

            String tmpString = this.getCallControl().getRemoteMonitorControl().getOriginator();

            final String originator = tmpString == null ? "Unknown Remote" : tmpString;

            final String localPeer = this.myJxtaView.getControl().getPeerName();

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    remoteMonitorPanel.setBorder(new TitledBorder(originator));

                    localMonitorPanel.setBorder(new TitledBorder(localPeer));


                    placeAcceptCallButton.setText(STRINGS.getString("action.vijxta.placecall"));

                }
            });

            showPanel(this.CONFIG_PANEL);

            showConfigPanel(this.CONFIG_VIDEO_SOURCE_PANEL);

            this.myJxtaView.updatePluginPanel(this, originator);


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_CONFIG_REQUEST_SENT) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_CONFIG_REQUEST + " Sent");


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_CONFIG_ACCEPT_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_CONFIG_ACCEPT + " Received");

            if (getCallControl().getLocalMonitorControl() == null) {


                EventQueue.invokeLater(new Runnable() {
                    public void run() {

                        errorMessageLabel.setText("LocalMonitorControl not available, null");


                    }
                });

                showPanel(this.ERROR_PANEL);

                if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                    LOG.info("LocalMonitorControl is NULL, Ending Call");
                }

                getCallControl().viewActionEndCall();

            }
            boolean transmit = getCallControl().getLocalMonitorControl().isTransmit();

            boolean receive = this.getCallControl().getRemoteMonitorControl().isReceive();

            Dimension transmitSize = null;
            Dimension receiveSize = null;

            int padding = 40;

            Dimension tmpSize = null;
            /** from the config elements aattempt to make all vid panels the same size */
            if (transmit) {

                tmpSize = this.getCallControl().getLocalMonitorControl().getFormatSize();

                transmitSize = new Dimension((int) tmpSize.getWidth() + padding, (int) tmpSize.getHeight() + padding);

                if (!receive) {

                    receiveSize = new Dimension((int) transmitSize.getWidth() + padding, (int) transmitSize.getHeight() + padding);
                }
            }
            if (receive) {
                if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                    LOG.info("RECEIVE");
                }
                tmpSize = this.getCallControl().getRemoteMonitorControl().getFormatSize();

                receiveSize = new Dimension((int) tmpSize.getWidth() + padding, (int) tmpSize.getHeight() + padding);

                if (!transmit) {

                    transmitSize = new Dimension((int) receiveSize.getWidth() + padding, (int) receiveSize.getHeight() + padding);
                }

            } else {
                if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                    LOG.info("NOT RECEIVE");
                }
            }

            final Dimension tSize = transmitSize;
            final Dimension rSize = receiveSize;
            if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
                LOG.info("transmitPanelSize " + transmitSize);
                LOG.info("receivePanelSize " + receiveSize);
            }

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    localMonitorPanel.setPreferredSize(tSize);

                    remoteMonitorPanel.setPreferredSize(rSize);

                    placeAcceptCallButton.setEnabled(true);

                    if (getCallControl().getLocalMonitorControl().getRefreshRateLabelTable() != null) {
                        refreshRateSlider.setLabelTable(getCallControl().getLocalMonitorControl().getRefreshRateLabelTable());
                    }
                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_CONFIG_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_CONFIG_REQUEST + " Received");


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_CONFIG_ACCEPT_SENT) {

            final boolean transmit = getCallControl().getLocalMonitorControl().isTransmit();

            final boolean receive = this.getCallControl().getRemoteMonitorControl().isReceive();

            Dimension transmitSize = null;
            Dimension receiveSize = null;

            int padding = 40;

            Dimension tmpSize = null;

            if (transmit) {

                tmpSize = this.getCallControl().getLocalMonitorControl().getFormatSize();

                transmitSize = new Dimension((int) tmpSize.getWidth() + padding, (int) tmpSize.getHeight() + padding);

                if (!receive) {

                    receiveSize = new Dimension((int) transmitSize.getWidth() + padding, (int) transmitSize.getHeight() + padding);
                }
            }
            if (receive) {

                tmpSize = this.getCallControl().getRemoteMonitorControl().getFormatSize();

                receiveSize = new Dimension((int) tmpSize.getWidth() + padding, (int) tmpSize.getHeight() + padding);

                if (!transmit) {

                    transmitSize = new Dimension((int) receiveSize.getWidth() + padding, (int) receiveSize.getHeight() + padding);
                }

            }

            final Dimension tSize = transmitSize;
            final Dimension rSize = receiveSize;


            final boolean isTransmit = transmit;

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    localMonitorPanel.setPreferredSize(tSize);

                    remoteMonitorPanel.setPreferredSize(rSize);

                    if (isTransmit) {

                        imageQualitySlider.setEnabled(true);

                        refreshRateSlider.setEnabled(true);
                    }

                    if (getCallControl().getLocalMonitorControl().getRefreshRateLabelTable() != null) {

                        refreshRateSlider.setLabelTable(getCallControl().getLocalMonitorControl().getRefreshRateLabelTable());

                    }

                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_START_REQUEST_SENT) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_START_REQUEST + " Sent");


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_START_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_START_REQUEST + " Received");

            if (this.getCallControl().isRemotePeerTransmit()) {

                this.getCallControl().getRemoteMonitorControl().obtainHardware();

            } else {
                // nothing to do... we are transmit only
            }

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    placeAcceptCallButton.setEnabled(true);

                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_START_ACCEPT_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_START_ACCEPT + " Received");

            if (this.getCallControl().isRemotePeerTransmit()) {

                this.getCallControl().getRemoteMonitorControl().obtainHardware();

            } else {
                // we are only transmitting
            }

        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_INCALL) {
            updateProtocolStateLabel("IN_CALL");
            EventQueue.invokeLater(new Runnable() {

                public void run() {
                    messageLabel.setText(STRINGS.getString("label.vojxta.connectedto") +
                            " " +
                            getCallControl().getRemoteMonitorControl().getOriginator());
                    placeAcceptCallButton.setEnabled(false);
                    holdResumeCallButton.setEnabled(true);
                    endCallButton.setEnabled(true);
                    if (getCallControl().getLocalVideoSourceType() !=
                            ViJxtaCallControl.NO_DEVICE &&
                            getCallControl().getLocalMonitorControl().isTransmit()) {
                        getCallControl().getLocalMonitorControl().startMonitor();
                        getCallControl().getLocalMonitorControl().startMonitorCapture();
                        getCallControl().getLocalMonitorControl().startTransmit();
                        if (getCallControl().getLocalMonitorControl().getMonitorComponent() ==
                                null) {
                            EventQueue.invokeLater(new Runnable() {

                                public void run() {
                                    errorMessageLabel.setText("LocalMonitorControl not available: No Video Device Chosen");
                                    showPanel(ERROR_PANEL);
                                }
                            });
                            if (Logging.SHOW_INFO &&
                                    LOG.isLoggable(Level.INFO)) {
                                LOG.info("LocalMonitorControlComponent is NULL, Ending Call");
                            }
                            getCallControl().viewActionEndCall();
                        } else {
                            localMonitorPanel.add(getCallControl().getLocalMonitorControl().getMonitorComponent());
                        }
                        String refreshRateLabel = getCallControl().getLocalMonitorControl().getRefreshRateUnitLabel();

                        refreshRateLabel = refreshRateLabel !=
                                null ? "Refresh Rate (" +
                                refreshRateLabel +
                                ")"
                                : "Refresh Rate";
                        refreshRateSlider.setBorder(new TitledBorder(refreshRateLabel));
                        refreshRateSlider.setEnabled(true);
                    }
                    if (getCallControl().remotePeerTransmit &&
                            getCallControl().getRemoteMonitorControl().isReceive()) {
                        getCallControl().getRemoteMonitorControl().startMonitor();
                        getCallControl().getRemoteMonitorControl().startReceive();
                        if (getCallControl().getRemoteMonitorControl().getMonitorComponent() ==
                                null) {
                            EventQueue.invokeLater(new Runnable() {

                                public void run() {
                                    errorMessageLabel.setText("RemoteMonitorControl not available");
                                }
                            });
                            if (Logging.SHOW_INFO &&
                                    LOG.isLoggable(Level.INFO)) {
                                LOG.info("RemoteMonitorControlComponent is Null, Ending Call");
                            }
                            // xxx: do we really need to termintate this call just
                            // bc we can't get a remote monitor component?
                            getCallControl().viewActionEndCall();
                        } else {
                            remoteMonitorPanel.add(getCallControl().getRemoteMonitorControl().getMonitorComponent());
                        }
                    }
                }
            });
            updateThread.start();
        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_HOLD_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_HOLD_REQUEST + " Received");

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(false);
                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_HOLD_ACCEPT_RECEIVED) {


            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_HOLD_ACCEPT + " Received");

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setText(STRINGS.getString("label.vijxta.resumecall"));

                    holdResumeCallButton.setEnabled(true);
                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_RESUME_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_RESUME_REQUEST + " Received");

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(true);

                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_RESUME_ACCEPT_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_RESUME_ACCEPT + " Received");

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setText(STRINGS.getString("label.vijxta.holdcall"));

                    holdResumeCallButton.setEnabled(true);
                }
            });


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_HANGUP_REQUEST_SENT) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_HANGUP_REQUEST + " Sent");

            this.updateThreadRun = false;


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_HANGUP_REQUEST_RECEIVED) {

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_HANGUP_REQUEST + " Received");

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(false);

                    endCallButton.setEnabled(false);
                }
            });

            this.updateThreadRun = false;


        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_DISCONNECT_REQUEST_RECEIVED) {

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(false);

                    endCallButton.setEnabled(false);
                }
            });

            updateProtocolStateLabel(ViJxtaCallControl.COMMAND_VIJXTA_DISCONNECT_REQUEST + " Received");

        } else if (protocolState == ViJxtaCallControl.SESSION_VIJXTA_DISCONNECTED) {


            setInSession(false);

            setInitiatedLocally(false);

            EventQueue.invokeLater(new Runnable() {
                public void run() {

                    holdResumeCallButton.setEnabled(false);

                    endCallButton.setEnabled(false);

                }
            });

            this.getCallControl().destroy();

            if (getCallControl().getErrorMessage() != null) {
                this.updateMessageLabel("ERROR! " + getCallControl().getErrorMessage());
            } else {

                this.updateMessageLabel("Idle. Ready to close.");
            }

            updateProtocolStateLabel("DISCONNECTED");

        }


    }

    private void updateProtocolStateLabel(final String protocolState) {
        if (protocolStateLabel != null) {
            EventQueue.invokeLater(new Runnable() {


                public void run() {

                    protocolStateLabel.setText(protocolState);
                }
            });
        }
    }

    private void updateJmfErrorLabel(final String message) {


        if (messageLabel != null) {
            EventQueue.invokeLater(new Runnable() {


                public void run() {

                    jmfErrorLabel.setText(message);
                    jmfErrorLabel.setVisible(true);
                }
            });
        }
    }

    private void updateMessageLabel(final String message) {


        if (messageLabel != null) {
            EventQueue.invokeLater(new Runnable() {


                public void run() {

                    messageLabel.setText(message);
                }
            });
        }
    }

    private void updateErrorMessageLabel(final String message) {


        if (messageLabel != null) {
            EventQueue.invokeLater(new Runnable() {


                public void run() {

                    errorMessageLabel.setText(message);
                }
            });
        }
    }

    private ViJxtaCallControl getCallControl() {

        return this.viJxtaCallControl;
    }

    public Dialog getDialog() {

        return this.viJxtaDialog;
    }

    public void dismiss() {
        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("Dismiss");
        }

        if (this.getCallControl() != null) {

            if (this.getCallControl().getLocalMonitorControl() != null) {

                this.getCallControl().getLocalMonitorControl().stopTransmit();

                this.getCallControl().getLocalMonitorControl().stopMonitorCapture();

                this.getCallControl().getLocalMonitorControl().stopMonitor();

                this.getCallControl().destroy();

            }


            if (this.getCallControl().getRemoteMonitorControl() != null) {

                this.getCallControl().getRemoteMonitorControl().stopReceive();

                this.getCallControl().getRemoteMonitorControl().stopMonitor();

            }

            this.getCallControl().destroy();
        }
    }


    private void setupLocalDevicesPanel() {


        DefaultListModel captureDevicesModel = new DefaultListModel();

        Iterator devices = null;

        if (getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.LOCAL_DEVICE) {

            devices = ((LocalDeviceMonitorControl) getCallControl().getLocalMonitorControl()).getCaptureDeviceNames();
        } else {

            devices = Collections.EMPTY_LIST.iterator();
        }

        if (devices.hasNext()) {


            while (devices.hasNext()) {

                String deviceName = (String) devices.next();


                captureDevicesModel.addElement(deviceName);
            }

            this.updateMessageLabel("Please choose capture device.");
        } else {


            noLocalCaptureDevicesFound = true;

            captureDevicesModel.addElement("No Capture Devices Found");

            if (getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.LOCAL_DEVICE) { // jmf installed but no cap devices found

                this.updateMessageLabel("No known capture devices available. Receving only.");
            } else {

                this.updateMessageLabel("Java Media Framework Not Present. Receving only.");

                this.updateJmfErrorLabel(this.JMF_ERROR_MESSAGE);
            }


        }

        captureDevicesList.setModel(captureDevicesModel);
    }


    public void setInitiatedLocally(boolean p_initiatedLocally) {

        initiatedLocally = p_initiatedLocally;

        setInSession(p_initiatedLocally);

    }

    protected boolean isInitiatedLocally() {

        return initiatedLocally;
    }

    public boolean isInSession() {

        return inSession;
    }

    protected void setInSession(boolean p_inSession) {

        inSession = p_inSession;
    }

    protected void showPanel(final String panelName) {


        EventQueue.invokeLater(new Runnable() {

            public void run() {

                cardLayout.show(deckPanel, panelName);

            }
        });
    }

    protected void showConfigPanel(final String panelName) {


        EventQueue.invokeLater(new Runnable() {

            public void run() {

                configCardLayout.show(configDeckPanel, panelName);

            }
        });
    }


    protected void setupNetworkedDevicesPanel() {


    }

    protected void localActionVideoSourceChosen() {

        if (localDevice) {

            getCallControl().setLocalVideoSourceType(ViJxtaCallControl.LOCAL_DEVICE);

            this.setupLocalDevicesPanel();

            this.showConfigPanel(this.CONFIG_LOCAL_DEVICES_PANEL);

        } else if (networkedDevice) {

            getCallControl().setLocalVideoSourceType(ViJxtaCallControl.NETWORKED_DEVICE);

            this.setupNetworkedDevicesPanel();

            this.showConfigPanel(this.CONFIG_NETWORKED_DEVICES_PANEL);

        } else if (noDevice) {

            getCallControl().setLocalVideoSourceType(ViJxtaCallControl.NO_DEVICE);

            this.setupOptionsPanel();

            this.showConfigPanel(this.CONFIG_LOCAL_OPTIONS_PANEL);
        }
    }

    public void localActionNetworkedCaptureDeviceChosen() {


        ((NetworkedDeviceMonitorControl) getCallControl().
                getLocalMonitorControl()).setAuthenticated(this.authenticationCheckBox.isSelected());

        ((NetworkedDeviceMonitorControl) getCallControl().
                getLocalMonitorControl()).setURL(this.networkedSourceURLTextField.getText());

        if (authenticationCheckBox.isSelected()) {

            ((NetworkedDeviceMonitorControl) getCallControl().
                    getLocalMonitorControl()).setUserName(this.authenticationUserNameTextField.getText());

            ((NetworkedDeviceMonitorControl) getCallControl().
                    getLocalMonitorControl()).setPassword(this.authenticationPasswordTextField.getText());

        }

        this.setupMonitorTestPanel();

        this.showConfigPanel(this.CONFIG_TEST_PANEL);
    }


    protected void localActionCaptureDeviceChosen() {

        if (noLocalCaptureDevicesFound) {

            this.setupOptionsPanel();

            this.showConfigPanel(this.CONFIG_LOCAL_OPTIONS_PANEL);
        } else {


            if (captureDevicesList.getSelectedIndex() == -1) {
                return;
            }

            String deviceName = (String) captureDevicesList.getSelectedValue();

            ((LocalDeviceMonitorControl) this.getCallControl().getLocalMonitorControl()).setCaptureDevice(deviceName);

            this.setupFormatsPanel();

            this.showConfigPanel(this.CONFIG_FORMATS_PANEL);
        }
    }

    private void setupFormatsPanel() {

        DefaultListModel formatsModel = new DefaultListModel();

        Iterator itr = ((LocalDeviceMonitorControl) this.getCallControl().getLocalMonitorControl()).getCaptureDeviceFormats();

        while (itr.hasNext()) {

            String formatSize = (String) itr.next();

            formatsModel.addElement(formatSize);
        }

        this.updateMessageLabel("Please choose video capture size.");

        formatsList.setModel(formatsModel);

    }

    private void setupOptionsPanel() {

        this.updateMessageLabel("Please choose desired options for this session.");


        if (this.noLocalCaptureDevicesFound ||
                getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.NO_DEVICE) {

            EventQueue.invokeLater(new Runnable() {

                public void run() {

                    transmitCheckBox.setSelected(false);

                    transmitCheckBox.setEnabled(false);
                }
            });
        } else {

            EventQueue.invokeLater(new Runnable() {

                public void run() {

                    transmitCheckBox.setSelected(true);

                    if (getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.NO_DEVICE) {

                        imageQualitySlider.setEnabled(false);

                    } else {
                        imageQualitySlider.setEnabled(true);
                    }
                }
            });
        }


        EventQueue.invokeLater(new Runnable() {

            public void run() {

                receiveCheckBox.setSelected(true);

                receiveCheckBox.setEnabled(true);

            }
        });

    }

    private void localActionFormatChosen() {

        if (formatsList.getSelectedIndex() == -1) {
            return;
        }

        String selectedFormat = (String) formatsList.getSelectedValue();

        ((LocalDeviceMonitorControl) this.getCallControl().getLocalMonitorControl()).setFormat(selectedFormat);

        this.setupMonitorTestPanel();


        this.showConfigPanel(this.CONFIG_TEST_PANEL);
    }

    private void setupMonitorTestPanel() {


        this.getCallControl().getLocalMonitorControl().obtainHardware();

        this.getCallControl().getLocalMonitorControl().startMonitor();


        for (int i = 0; i < 5; i++) {

            if (getCallControl().getLocalMonitorControl().getFormatSize().width != 0) {

                break;
            }

            try {

                Thread.sleep(1000);
            } catch (InterruptedException ix) {
                ix.printStackTrace();
            }
        }

        Dimension size = getCallControl().getLocalMonitorControl().getFormatSize();

        LOG.info("testMonitorPanel Size " + size);

        monitorTestPanel.setSize(new Dimension(size.width + 40, size.height + 40));

        monitorTestPanel.add(this.getCallControl().getLocalMonitorControl().getMonitorComponent());

        this.updateMessageLabel("Click Next if you see live video.");

    }

    protected void localActionMonitorTestUnSuccessful() {

        this.getCallControl().getLocalMonitorControl().resetMonitor();

        if (getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.NETWORKED_DEVICE) {

            this.showConfigPanel(this.CONFIG_NETWORKED_DEVICES_PANEL);

        } else if (getCallControl().getLocalVideoSourceType() == ViJxtaCallControl.LOCAL_DEVICE) {

            this.showConfigPanel(this.CONFIG_LOCAL_DEVICES_PANEL);
        }
    }

    protected void localActionMonitorTestSuccessful() {

        //this.monitorTestPanel.remove (this.getCallControl ().getLocalMonitorControl ().getMonitorComponent ());

        this.monitorTestComponent = null;

        this.setupOptionsPanel();

        this.showConfigPanel(this.CONFIG_LOCAL_OPTIONS_PANEL);


    }

    protected void localActionApplyConfigSettings() {


        getCallControl().getLocalMonitorControl().setTransmit(this.transmitCheckBox.isSelected());

        this.getCallControl().getRemoteMonitorControl().setReceive(this.receiveCheckBox.isSelected());

        if (Logging.SHOW_INFO && LOG.isLoggable(Level.INFO)) {
            LOG.info("Apply Config Settings");
            LOG.info("LocalMonitor Control Transmit = " +
                    getCallControl().getLocalMonitorControl().isTransmit());
            LOG.info("RemoteMonitor Control Receive  = " +
                    getCallControl().getRemoteMonitorControl().isReceive());
        }

        this.getCallControl().viewActionConfigured();


        this.updateMessageLabel("Ready.");

        this.showPanel(this.CALL_CONTROL_PANEL);

    }

    protected void localActionPlaceAcceptCall() {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                placeAcceptCallButton.setEnabled(false);

            }
        });

        if (placeAcceptCallButton.getText().equals(STRINGS.getString("action.vijxta.placecall"))) {

            this.getCallControl().viewActionPlaceCall();

        } else if (placeAcceptCallButton.getText().equals(STRINGS.getString("action.vijxta.acceptcall"))) {

            this.getCallControl().viewActionAcceptCall();
        }

    }

    private void localActionDownloadJmf() {
        try {

            ExecFactory.getExec().execDocument(new URL(URL_JMF_DOWNLOAD));
        } catch (MalformedURLException mux) {

            mux.printStackTrace();
        }
    }

    private void localActionImageQualityChanged(int value) {


        getCallControl().getLocalMonitorControl().setImageCompression(value);

    }

    protected void localActionHoldResumeCall() {

        String buttonText = null;

        if (this.getCallControl().getProtocolState() == this.getCallControl().SESSION_VIJXTA_INCALL) {

            this.getCallControl().viewActionHoldCall();

            buttonText = STRINGS.getString("action.vijxta.holdcall");

        } else if (this.getCallControl().getProtocolState() == this.getCallControl().SESSION_VIJXTA_HOLDING) {

            this.getCallControl().viewActionResumeCall();

            buttonText = STRINGS.getString("action.vijxta.resumecall");
        }

        final String finalButtonText = buttonText;

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                holdResumeCallButton.setText(finalButtonText);

            }
        });

    }

    protected void localActionEndCall() {

        EventQueue.invokeLater(new Runnable() {

            public void run() {

                placeAcceptCallButton.setEnabled(false);

                holdResumeCallButton.setEnabled(false);

                endCallButton.setEnabled(false);

            }
        });

        this.getCallControl().viewActionEndCall();

    }

    private void UI() {

        this.setPreferredSize(new Dimension(440, 300));

        double sizes[][] = {{TableLayout.FILL}, {TableLayout.PREFERRED, TableLayout.FILL}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel uiPanel = new JPanel(tbl);

        uiPanel.add(buildMessagePanel(), "0,0,l,c");

        cardLayout = new CardLayout();
        deckPanel = new JPanel(cardLayout);

        deckPanel.add(buildNoResponsePanel(), NO_RESPONSE_PANEL);

        deckPanel.add(buildConfigPanel(), CONFIG_PANEL);

        deckPanel.add(this.buildCallControlPanel(), this.CALL_CONTROL_PANEL);

        deckPanel.add(this.buildStatsPanel(), this.STATS_PANEL);

        deckPanel.add(this.buildErrorPanel(), this.ERROR_PANEL);

        deckPanel.add(this.buildIdlePanel(), this.IDLE_PANEL);


        uiPanel.add(deckPanel, "0,1,c,c");

        showPanel(this.NO_RESPONSE_PANEL);

        this.add(uiPanel);
    }

    private JPanel buildErrorPanel() {

        double sizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel panel = new JPanel(tbl);

        errorMessageLabel = new JLabel("ERROR");

        panel.add(errorMessageLabel, "0,0");

        return panel;

    }

    private JPanel buildMessagePanel() {

        double b = 5;
        double sizes[][] = {{b, TableLayout.FILL, b},
                {b, TableLayout.PREFERRED, b, TableLayout.PREFERRED, b, TableLayout.PREFERRED, b}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel panel = new JPanel(tbl);

        productLabel = new JLabel("viJXTA .01");
        //productLabel.setFont (new Font ("Arial", Font.BOLD, 14));
        productLabel.setForeground(new Color(0.0f, 0.0f, 0.0f, 0.5f));
        panel.add(productLabel, "1,1,l,c");

        protocolStateLabel = new JLabel("protocolState");
        panel.add(protocolStateLabel, "1,3,l,c");

        messageLabel = new JLabel("Message");
        messageLabel.setFont(new Font("Arial", Font.BOLD, 14));
        messageLabel.setForeground(new Color(0.0f, 0.0f, 0.0f));
        panel.add(messageLabel, "1,5,c,c");

        return panel;
    }

    private JPanel buildConfigPanel() {

        configCardLayout = new CardLayout();

        configDeckPanel = new JPanel(configCardLayout);

        configDeckPanel.add(buildConfigChooseVideoSourcePanel(), this.CONFIG_VIDEO_SOURCE_PANEL);

        configDeckPanel.add(buildConfigLocalDevicesPanel(), this.CONFIG_LOCAL_DEVICES_PANEL);

        configDeckPanel.add(buildConfigNetworkedDevicesPanel(), this.CONFIG_NETWORKED_DEVICES_PANEL);

        configDeckPanel.add(buildConfigFormatsPanel(), this.CONFIG_FORMATS_PANEL);

        configDeckPanel.add(this.buildConfigLocalOptionsPanel(), this.CONFIG_LOCAL_OPTIONS_PANEL);

        configDeckPanel.add(buildConfigTestPanel(), this.CONFIG_TEST_PANEL);

        this.showConfigPanel(this.CONFIG_VIDEO_SOURCE_PANEL);

        return configDeckPanel;

    }

    private JPanel buildConfigChooseVideoSourcePanel() {

        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel panel = new JPanel(tbl);
        panel.setBorder(new TitledBorder("VideoSource"));

        JRadioButton localDeviceRadioButton = new JRadioButton("Local Webcam (FireWire 1394 or USB)");
        panel.add(localDeviceRadioButton, "0,0");
        localDeviceRadioButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                localDevice = e.getStateChange() == e.SELECTED ? true : false;
            }
        });

        JRadioButton networkedDeviceRadioButton = new JRadioButton("Networked Webcam (URL)");
        panel.add(networkedDeviceRadioButton, "0,1");
        networkedDeviceRadioButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                networkedDevice = e.getStateChange() == e.SELECTED ? true : false;
            }
        });

        JRadioButton noDeviceRadioButton = new JRadioButton("No Webcam (Receive Only)");
        panel.add(noDeviceRadioButton, "0,2");
        noDeviceRadioButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                noDevice = e.getStateChange() == e.SELECTED ? true : false;
            }
        });

        ButtonGroup bGroup = new ButtonGroup();

        bGroup.add(localDeviceRadioButton);
        bGroup.add(networkedDeviceRadioButton);
        bGroup.add(noDeviceRadioButton);

        JButton nextButton = new JButton("Next >");
        panel.add(nextButton, "0,3,c,c");
        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionVideoSourceChosen();
            }
        });

        return panel;

    }


    private JPanel buildIdlePanel() {
        double b = 20;
        double sizes[][] = {{b, TableLayout.FILL, b},
                {b, TableLayout.FILL, b}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel panel = new JPanel(tbl);

        JLabel tempLabel = new JLabel("LOGO Goes Here.");
        panel.add(tempLabel, "1,1,c,c");


        return panel;
    }

    private JPanel buildNoResponsePanel() {

        double sizes[][] = {{TableLayout.FILL},
                {TableLayout.FILL}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel panel = new JPanel(tbl);


        return panel;
    }

    private JPanel buildConfigNetworkedDevicesPanel() {
        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel devicePanel = new JPanel(tbl);
        devicePanel.setBorder(new TitledBorder("Networked Webcam Config"));

        double authenticationSizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};

        TableLayout authenticationTbl = new TableLayout(authenticationSizes);

        JPanel authenticationPanel = new JPanel(authenticationTbl);
        devicePanel.add(authenticationPanel, "0,2,c,c");
        authenticationPanel.setBorder(new TitledBorder("Authentication"));

        // main panel
        JLabel label = null;
        label = new JLabel("The Remote WebCams URL");
        devicePanel.add(label, "0,0");

        networkedSourceURLTextField = new JTextField(20);
        devicePanel.add(networkedSourceURLTextField, "0,1");

        // authentication panel

        authenticationCheckBox = new JCheckBox("Use Authentication");
        authenticationPanel.add(authenticationCheckBox, "0,0");
        authenticationCheckBox.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {

                boolean authenticated = e.getStateChange() == e.SELECTED;

                authenticationUserNameTextField.setEnabled(authenticated);

                authenticationPasswordTextField.setEnabled(authenticated);

                ((NetworkedDeviceMonitorControl) getCallControl().
                        getLocalMonitorControl()).
                        setAuthenticated(authenticated);
            }
        });

        label = new JLabel("User Name");
        authenticationPanel.add(label, "0,1");

        authenticationUserNameTextField = new JTextField(10);
        authenticationPanel.add(authenticationUserNameTextField, "0,2");
        authenticationUserNameTextField.setEnabled(false);

        label = new JLabel("Password");
        authenticationPanel.add(label, "0,3");

        authenticationPasswordTextField = new JPasswordField(10);
        authenticationPanel.add(authenticationPasswordTextField, "0,4");
        authenticationPasswordTextField.setEnabled(false);


        JButton nextButton = new JButton("Next >");
        devicePanel.add(nextButton, "0,3,c,c");
        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionNetworkedCaptureDeviceChosen();
            }
        });

        return devicePanel;
    }


    private JPanel buildConfigLocalDevicesPanel() {
        double b = 10;
        double sizes[][] = {{TableLayout.FILL},
                {TableLayout.PREFERRED, b, TableLayout.PREFERRED, 20, TableLayout.PREFERRED}};

        TableLayout tbl = new TableLayout(sizes);

        JPanel devicePanel = new JPanel(tbl);


        captureDevicesList = new JList();
        captureDevicesList.setBorder(new TitledBorder("Capture Devices"));

        devicePanel.add(captureDevicesList, "0,0,c,c");

        JButton nextButton = new JButton("Next >");
        devicePanel.add(nextButton, "0,2,c,c");
        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionCaptureDeviceChosen();
            }
        });

        jmfErrorLabel = new JLabel("");
        devicePanel.add(jmfErrorLabel, "0,4,c,c");
        jmfErrorLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent me) {

                localActionDownloadJmf();
            }
        });
        return devicePanel;

    }

    private JPanel buildConfigFormatsPanel() {
        double b = 10;
        double sizes[][] = {{TableLayout.FILL},
                {TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);

        JPanel formatsPanel = new JPanel(tbl);

        formatsList = new JList();
        formatsList.setBorder(new TitledBorder("Video Frame Sizes"));

        formatsPanel.add(formatsList, "0,0,c,c");

        JButton nextButton = new JButton("Next >");
        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                localActionFormatChosen();
            }
        });

        formatsPanel.add(nextButton, "0,1, c, c");

        return formatsPanel;

    }

    private JPanel buildConfigTestPanel() {


        double b = 10;
        double sizes[][] = {{TableLayout.PREFERRED}, {TableLayout.PREFERRED, b, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel configTestPanel = new JPanel(tbl);


        monitorTestPanel = new JPanel();
        monitorTestPanel.setBorder(new TitledBorder("Monitor Panel"));
        configTestPanel.add(monitorTestPanel, "0,0");

        double actionPanelSizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED}, {TableLayout.PREFERRED}};
        TableLayout actionTbl = new TableLayout(actionPanelSizes);
        JPanel actionPanel = new JPanel(actionTbl);

        JButton nextButton = new JButton("Next >");
        actionPanel.add(nextButton, "1,0");

        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                localActionMonitorTestSuccessful();
            }
        });


        JButton backButton = new JButton("< Back");
        actionPanel.add(backButton, "0, 0");

        backButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                localActionMonitorTestUnSuccessful();
            }
        });

        configTestPanel.add(actionPanel, "0, 2, c, c");

        return configTestPanel;

    }

    private JPanel buildConfigLocalOptionsPanel() {


        double b = 10;
        double sizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED}, {TableLayout.PREFERRED, TableLayout.PREFERRED}};

        TableLayout tbl = new TableLayout(sizes);
        JPanel optionsPanel = new JPanel(tbl);


        double transmitSizes[][] = {{TableLayout.PREFERRED}, {TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout transmitTbl = new TableLayout(transmitSizes);
        JPanel transmitPanel = new JPanel(transmitTbl);
        transmitPanel.setBorder(new TitledBorder(STRINGS.getString("label.vijxta.transmitoptions")));
        optionsPanel.add(transmitPanel, "0, 0");


        transmitCheckBox = new JCheckBox(STRINGS.getString("label.vijxta.transmit"));
        transmitCheckBox.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {

                imageQualitySlider.setEnabled(e.getStateChange() == e.SELECTED ? true : false);
            }
        });

        transmitPanel.add(transmitCheckBox, "0, 0");

        imageQualitySlider = new JSlider(SwingConstants.HORIZONTAL,
                Monitor.MINIMUM_IMAGE_COMPRESSION,
                Monitor.MAXIMUM_IMAGE_COMPRESSION,
                Monitor.DEFAULT_IMAGE_COMPRESSION);
        transmitPanel.add(imageQualitySlider, "0, 1");

        imageQualitySlider.setBorder(new TitledBorder("Video Quality"));
        imageQualitySlider.setLabelTable(imageQualityLabelTable);
        imageQualitySlider.setMajorTickSpacing(1);
        imageQualitySlider.setPaintLabels(true);
        imageQualitySlider.setPaintTicks(false);
        imageQualitySlider.setSnapToTicks(true);
        imageQualitySlider.setEnabled(false);
        imageQualitySlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent ce) {

                localActionImageQualityChanged(imageQualitySlider.getValue());

            }
        });


        double receiveSizes[][] = {{TableLayout.PREFERRED}, {TableLayout.PREFERRED}};
        TableLayout receiveTbl = new TableLayout(receiveSizes);
        JPanel receivePanel = new JPanel(receiveTbl);
        receivePanel.setBorder(new TitledBorder(STRINGS.getString("label.vijxta.receiveoptions")));
        optionsPanel.add(receivePanel, "1, 0");


        receiveCheckBox = new JCheckBox(STRINGS.getString("label.vijxta.receive"));
        receiveCheckBox.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                getCallControl().getRemoteMonitorControl().setReceive(receiveCheckBox.isSelected());
            }
        });
        receivePanel.add(receiveCheckBox, "0,0");


        JButton actionButton = new JButton(STRINGS.getString("action.ok"));
        optionsPanel.add(actionButton, "0, 1,c,c");

        actionButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionApplyConfigSettings();
            }
        });


        return optionsPanel;
    }

    private JPanel buildCallControlPanel() {

        double b = 10;
        double sizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel callControlPanel = new JPanel(tbl);

        //-----------
        double monitorSizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED},
                {TableLayout.PREFERRED}};
        TableLayout monitorTbl = new TableLayout(monitorSizes);
        JPanel monitorPanel = new JPanel(monitorTbl);
        callControlPanel.add(monitorPanel, "0,0,c,c");


        remoteMonitorPanel = new JPanel();
        remoteMonitorPanel.setPreferredSize(new Dimension(200, 140));
        remoteMonitorPanel.setBorder(new TitledBorder("Remote"));
        monitorPanel.add(remoteMonitorPanel, "2,0,c,t");


        double localSizes[][] = {{TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout localTbl = new TableLayout(localSizes);
        JPanel localPanel = new JPanel(localTbl);
        monitorPanel.add(localPanel, "0, 0, c, t");


        localMonitorPanel = new JPanel();
        localMonitorPanel.setPreferredSize(new Dimension(200, 140));
        localMonitorPanel.setBorder(new TitledBorder("Local"));
        localPanel.add(localMonitorPanel, "0,0");

        refreshRateSlider = new JSlider(SwingConstants.HORIZONTAL,
                Monitor.MINIMUM_FRAMES_PER_SECOND,
                Monitor.MAXIMUM_FRAMES_PER_SECOND,
                Monitor.DEFAULT_FRAMES_PER_SECOND);
        refreshRateSlider.setEnabled(false);
        localPanel.add(refreshRateSlider, "0, 1");


        refreshRateSlider.setFont(new Font(this.getFont().getName(), this.getFont().getStyle(), 13));
        refreshRateSlider.setPaintLabels(true);
        refreshRateSlider.setBorder(new TitledBorder(null, "Refresh Rate", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION));
        refreshRateSlider.setPaintTicks(false);
        refreshRateSlider.setSnapToTicks(true);
        refreshRateSlider.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent ce) {

                getCallControl().getLocalMonitorControl().setRefreshRate(refreshRateSlider.getValue());

                refreshRateLabel.setText(String.valueOf(refreshRateSlider.getValue()));
            }
        });
        //-------------

        double actionSizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED},
                {TableLayout.PREFERRED}};
        TableLayout actionTbl = new TableLayout(actionSizes);
        JPanel actionPanel = new JPanel(actionTbl);
        actionPanel.setBorder(null);

        callControlPanel.add(actionPanel, "0,1,c,c");


        placeAcceptCallButton = new JButton(STRINGS.getString("action.vijxta.placecall"));
        placeAcceptCallButton.setEnabled(false);
        actionPanel.add(placeAcceptCallButton, "0,0");

        placeAcceptCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionPlaceAcceptCall();
            }
        });


        holdResumeCallButton = new JButton(STRINGS.getString("action.vijxta.holdcall"));
        holdResumeCallButton.setEnabled(false);
        actionPanel.add(holdResumeCallButton, "1,0");

        holdResumeCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionHoldResumeCall();
            }
        });


        endCallButton = new JButton(STRINGS.getString("action.vijxta.endcall"));
        endCallButton.setEnabled(true);
        actionPanel.add(endCallButton, "2,0");

        endCallButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                localActionEndCall();
            }
        });

        statsButton = new JButton(STRINGS.getString("action.vojxta.stats"));
        actionPanel.add(statsButton, "3,0");

        statsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {

                showPanel(STATS_PANEL);
            }
        });

        // it's safe to take this out of the ui
        JButton stopMonitorsButton = new JButton("STOP MONITORS");
        //actionPanel.add (stopMonitorsButton,"4,0");

        stopMonitorsButton.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                if (Logging.SHOW_INFO &&
                        LOG.isLoggable(Level.INFO)) {
                    LOG.info("StopMonitor Button Pressed, Ending Call");
                }
                getCallControl().viewActionEndCall();
            }
        });

        return callControlPanel;

    }


    private JPanel buildStatsTrafficPanel() {
        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel trafficPanel = new JPanel(tbl);
        trafficPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.traffic")));

        JLabel label = null;
        JSeparator sep = null;

        label = new JLabel(STRINGS.getString("label.vojxta.received"));
        trafficPanel.add(label, "0,0, 1,0");

        label = new JLabel(STRINGS.getString("label.vojxta.sent"));
        trafficPanel.add(label, "3,0, 4,0");

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        trafficPanel.add(sep, "0,1, 1,1");

        sep = new JSeparator(SwingConstants.HORIZONTAL);
        trafficPanel.add(sep, "3,1, 4,1");

        sep = new JSeparator(SwingConstants.VERTICAL);
        trafficPanel.add(sep, "2,1, 2, 6");

        label = new JLabel(STRINGS.getString("label.vojxta.messages"));
        trafficPanel.add(label, "0,2");

        messagesReceivedLabel = new JLabel("0");
        trafficPanel.add(messagesReceivedLabel, "1,2");

        label = new JLabel(STRINGS.getString("label.vojxta.messages"));
        trafficPanel.add(label, "4,2");

        messagesSentLabel = new JLabel("0");
        trafficPanel.add(messagesSentLabel, "3,2");

        label = new JLabel(STRINGS.getString("label.vojxta.bytes"));
        trafficPanel.add(label, "0, 3");

        bytesReceivedLabel = new JLabel("0");
        trafficPanel.add(bytesReceivedLabel, "1,3");

        label = new JLabel(STRINGS.getString("label.vojxta.bytes"));
        trafficPanel.add(label, "4,3");

        bytesSentLabel = new JLabel("0");
        trafficPanel.add(bytesSentLabel, "3,3");

        label = new JLabel(STRINGS.getString("label.vojxta.messagespersecond"));
        trafficPanel.add(label, "0,4");


        incomingMessagesPerSecondLabel = new JLabel("0");
        trafficPanel.add(incomingMessagesPerSecondLabel, "1,4");

        label = new JLabel(STRINGS.getString("label.vojxta.messagespersecond"));
        trafficPanel.add(label, "4,4");

        outgoingMessagesPerSecondLabel = new JLabel("0");
        trafficPanel.add(outgoingMessagesPerSecondLabel, "3,4");

        label = new JLabel(STRINGS.getString("label.vojxta.bytespersecond"));
        trafficPanel.add(label, "0,5");

        incomingBytesPerSecondLabel = new JLabel("0");
        trafficPanel.add(incomingBytesPerSecondLabel, "1,5");

        label = new JLabel(STRINGS.getString("label.vojxta.bytespersecond"));
        trafficPanel.add(label, "4,5");

        outgoingBytesPerSecondLabel = new JLabel("0");
        trafficPanel.add(outgoingBytesPerSecondLabel, "3,5");


        label = new JLabel("Buffer Size");
        trafficPanel.add(label, "0,6");

        incomingBufferSizeLabel = new JLabel("0");
        trafficPanel.add(incomingBufferSizeLabel, "1,6");

        label = new JLabel("Buffer Size");
        trafficPanel.add(label, "4,6");

        outgoingBufferSizeLabel = new JLabel("0");
        trafficPanel.add(outgoingBufferSizeLabel, "3,6");

        return trafficPanel;

    }

    private JPanel buildStatsImagePanel() {
        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel imagePanel = new JPanel(tbl);
        imagePanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vijxta.image")));

        JLabel label = null;
        JSeparator sep = null;

        label = new JLabel(STRINGS.getString("label.vijxta.encodetime"));
        imagePanel.add(label, "0,0");

        encodeTimeLabel = new JLabel("0");
        imagePanel.add(encodeTimeLabel, "1,0");

        label = new JLabel(STRINGS.getString("label.vijxta.decodetime"));
        imagePanel.add(label, "0,1");

        decodeTimeLabel = new JLabel("0");
        imagePanel.add(decodeTimeLabel, "1,1");

        label = new JLabel(STRINGS.getString("label.vojxta.averageencodetime"));
        imagePanel.add(label, "0,2");

        averageEncodeTimeLabel = new JLabel("0");
        imagePanel.add(averageEncodeTimeLabel, "1,2");

        label = new JLabel(STRINGS.getString("label.vojxta.averagedecodetime"));
        imagePanel.add(label, "0,3");

        averageDecodeTimeLabel = new JLabel("0");
        imagePanel.add(averageDecodeTimeLabel, "1,3");


        label = new JLabel(STRINGS.getString("label.vijxta.imageencodequality"));
        imagePanel.add(label, "0,4");

        incomingImageCompressionLabel = new JLabel("0");
        imagePanel.add(incomingImageCompressionLabel, "1,4");

        label = new JLabel(STRINGS.getString("label.vijxta.imagedecodequality"));
        imagePanel.add(label, "0,5");

        outgoingImageCompressionLabel = new JLabel("0");
        imagePanel.add(outgoingImageCompressionLabel, "1,5");

        label = new JLabel(STRINGS.getString("label.vijxta.framespersecond"));
        imagePanel.add(label, "0,6");

        this.refreshRateLabel = new JLabel();
        imagePanel.add(refreshRateLabel, "1,6");

        return imagePanel;
    }

    private JPanel buildStatsChronoPanel() {
        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED},
                {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel chronoPanel = new JPanel(tbl);
        chronoPanel.setBorder(new TitledBorder(null, STRINGS.getString("label.vojxta.chronometer")));

        JLabel label = null;
        JSeparator sep = null;


        label = new JLabel(STRINGS.getString("label.vojxta.callstarttime"));
        chronoPanel.add(label, "0,0");

        callStartTimeLabel = new JLabel("");
        chronoPanel.add(callStartTimeLabel, "0, 1");

        label = new JLabel(STRINGS.getString("label.vojxta.elapsedtime"));

        chronoPanel.add(label, "0,2");

        callElapsedTimeLabel = new JLabel("");

        chronoPanel.add(callElapsedTimeLabel, "0,3");

        label = new JLabel(STRINGS.getString("label.vojxta.callendtime"));

        chronoPanel.add(label, "0,4");

        callEndTimeLabel = new JLabel("N/A");

        chronoPanel.add(callEndTimeLabel, "0,5");

        label = new JLabel(STRINGS.getString("label.vojxta.roundtriptime"));

        chronoPanel.add(label, "0,6");

        roundTripTimeLabel = new JLabel("");

        chronoPanel.add(roundTripTimeLabel, "0,7");

        return chronoPanel;
    }

    private JPanel buildStatsActionPanel() {
        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED}, {TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel actionPanel = new JPanel(tbl);

        actionPanel.setBorder(null);

        JButton backButton = new JButton(STRINGS.getString("action.vojxta.back"));
        actionPanel.add(backButton, "0,0");
        backButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                showPanel(CALL_CONTROL_PANEL);
            }
        });

        return actionPanel;
    }

    /**
     * build the statistics panel
     */
    private JPanel buildStatsPanel() {

        double b = 5;
        double sizes[][] = {{TableLayout.PREFERRED, TableLayout.PREFERRED}, {TableLayout.PREFERRED, TableLayout.PREFERRED, TableLayout.PREFERRED}};
        TableLayout tbl = new TableLayout(sizes);
        JPanel statsPanel = new JPanel(tbl);

        statsPanel.setBorder(null);

        statsPanel.add(this.buildStatsTrafficPanel(), "0,0");

        statsPanel.add(this.buildStatsImagePanel(), "1,0");

        statsPanel.add(this.buildStatsChronoPanel(), "1,1");

        statsPanel.add(this.buildStatsActionPanel(), "1,2, r, c");

        return statsPanel;


    }

}
